package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	"iot-base/common/cache"
	"iot-base/common/crudextend"
	"iot-base/common/ctrltype"
	"iot-base/common/dbconn"
	"iot-base/common/dbobj"
	"iot-base/common/logger"
	"iot-base/common/notify"
	redis "iot-base/common/redis"

	"gorm.io/gorm"
)

type Ipc struct {
	IpcID    string `gorm:"primarykey" json:"ipc_id"`
	B        string `json:"b"`
	P        string `json:"p"`
	BoxID    string `gorm:"uniqueIndex:ipc_box;not null" json:"box_id"`
	IDInBox  string `gorm:"uniqueIndex:ipc_box;not null" json:"id_in_box"`
	PlayAddr string `json:"play_addr"`
	RTSP     string `json:"rtsp"`
	IP       string `gorm:"uniqueIndex:ipc_box;not null;default:0.0.0.0" json:"ip"`
	no       int
}

func init() {
	dbconn.DBConnection.AutoMigrate(&Ipc{})
}
func (pIPC *Ipc) createID() {
	idinBox := pIPC.IDInBox
	pIPC.no = -1
	if pIPC.IDInBox != "" {
		idinBox = strings.Replace(pIPC.IDInBox, "Cam", "", 1)
	}
	if idinBox != "" {
		pIPC.no, _ = strconv.Atoi(idinBox)
	}
	pIPC.IpcID = pIPC.BoxID + "." + idinBox

	//pIPC.Thing.UID = pIPC.IpcID
}
func (pIPC *Ipc) save() error {
	if pIPC != nil && pIPC.B != "" && pIPC.P != "" && pIPC.BoxID != "" {
		err := dbconn.DBConnection.Transaction(func(tx *gorm.DB) error {
			pIPC.createID()
			var oldIPC Ipc
			oldIPC.IpcID = pIPC.IpcID
			err := dbconn.DBConnection.First(&oldIPC).Error
			if err != nil {
				err = dbconn.DBConnection.Create(pIPC).Error
				//return err
			} else {
				err = dbconn.DBConnection.Save(pIPC).Error
			}

			return err

		})
		if err == nil {
			pIPC.RunSetIPC()
		}
		return err
	}
	return errors.New("Ipc params 为空")
}

func (pIPC *Ipc) remove() error {
	if pIPC != nil {
		return dbconn.DBConnection.Delete(pIPC).Error
	}
	return errors.New("Ipc params 为空")
}
func initIPC(qmap map[string]string) *Ipc {
	pIPC := &Ipc{
		IpcID:    qmap["ipc_id"],
		B:        qmap["b"],
		P:        qmap["p"],
		BoxID:    qmap["box_id"],
		IDInBox:  qmap["id_in_box"],
		PlayAddr: qmap["play_addr"],
		RTSP:     qmap["rtsp"],
		IP:       qmap["ip"],
	}
	return pIPC
}
func ipcSave(qmap map[string]string) ([]map[string]interface{}, error) {
	pIPC := initIPC(qmap)
	err := pIPC.save()
	if err == nil {
		expression, _ := json.Marshal(pIPC)
		pLinkage := &cache.DevLinkage{
			TID:        pIPC.BoxID,
			Trigger:    "online",
			LType:      pIPC.IDInBox,
			Expression: expression,
		}
		pLinkage.SaveOrCreate()
	}

	return nil, err

}

func createIPC(qmap map[string]string, stationID string) {

	pIPC := initIPC(qmap)
	if pIPC != nil {
		pIPC.createID()
		var thing dbobj.Thing
		thing.UID = pIPC.IpcID
		thing.ModelID = "m_ipc"
		//thing.UsedTime = time.Now()
		thing.StatusUsed = 1
		dbconn.DBConnection.Transaction(func(tx *gorm.DB) error {
			var count int64
			var err error
			tx.Model(&dbobj.Thing{}).Where("uid=?", pIPC.IpcID).Count(&count)
			var ts dbobj.ThingStation
			ts.ThingID = thing.UID
			ts.StationID = stationID

			ts.ModelID = thing.ModelID

			thing.SName = "摄像机" + qmap["cno"]
			var thingparams dbobj.ThingParam

			dbconn.DBConnection.Delete(&thingparams, "thing_id=?", thing.UID)
			thingparams.ParamID = "ip"
			thingparams.ParamValue = qmap["ip"]
			thingparams.ThingID = thing.UID
			if count == 0 {
				sid, _ := redis.IncrBy("g.m_smartBoxForPolice.uid", 1).Result()
				ts.SNO = int(sid)
				err = tx.Create(&thing).Error
				if err != nil {
					return err
				}
				err = tx.Create(&ts).Error
				if err != nil {
					return err
				}

			} else {
				err = tx.Save(&thing).Error
				if err != nil {
					return err
				}
				err = tx.Update(ts.ThingID, &ts).Error
				if err != nil {
					return err
				}

				//tx.Where("thing_id=? and param_id=?",)
			}
			err = tx.Create(&thingparams).Error
			if err != nil {
				return err
			}
			err = pIPC.save()
			return err

		})
		//thing.IsProxy = false
		//thing.
	}
}

func ipcRemove(qmap map[string]string) ([]map[string]interface{}, error) {
	id := qmap["ipc_id"]
	ids := strings.Split(id, ".")
	if len(ids) == 2 {
		pIPC := &Ipc{
			IpcID:   qmap["ipc_id"],
			IDInBox: "Cam" + ids[1],
			BoxID:   ids[0],
			B:       "-1",
			P:       "0",
			IP:      "0.0.0.0",
		}
		pIPC.no, _ = strconv.Atoi(ids[1])
		err := pIPC.remove()
		if err == nil {
			pIPC.RunSetIPC()
		}
		return nil, err
	}
	return nil, errors.New("id 格式错误")

}

func RunSetIPCs(tid string) {
	for i := 1; i < 8; i++ {
		id := fmt.Sprintf("Cam%d", i)
		expression := cache.GetExpressionByTrigger(tid, "online", id)
		if len(expression) > 0 {
			var ipc Ipc
			err := json.Unmarshal(expression, &ipc)
			if err == nil {
				(&ipc).RunSetIPC()
			}
		}
	}

}

func (ipc *Ipc) RunSetIPC() {
	params := make(map[string]interface{})
	params["B"] = ipc.B
	params["P"] = ipc.P
	params["Cam"] = strconv.Itoa(ipc.no)
	params["IP"] = ipc.IP
	params["UID"] = ipc.IpcID
	var ctrlCmd ctrltype.CtrlCmd
	ctrlCmd.Params = params
	ctrlCmd.ID = "IPCSet"
	ctrlCmd.ThingID = ipc.BoxID
	notify.Ctrl(&ctrlCmd, time.Second*10, func(pResult *ctrltype.CtrlResult) {
		logger.SLog.Info("-----send ctrl cmd", ipc.BoxID, params, pResult)
	}, false)
}

type ipStationID struct {
	//IP         string
	StationID string
	ThingID   string
	//ParamValue string
}

func getStationByID(ip string) (string, string, error) {
	var ipstation ipStationID
	err := dbconn.DBConnection.Model(&dbobj.ThingParam{}).Select("station_id", "thing_params.thing_id").
		Where("param_value=? and param_id=?", ip, "IP").
		Joins("left join thing_stations on thing_stations.thing_id=thing_params.thing_id ").
		Scan(&ipstation).Error
	if err == nil {
		bid := ipstation.ThingID
		stationID := ipstation.StationID
		return bid, stationID, err
	}
	return "", "", err
}
func batchIPCs(msg *crudextend.HTTPMsg) crudextend.HTTPMsgResp {
	var ret crudextend.HTTPMsgResp
	if msg.Infos != nil {
		var bip = ""
		mapParams := make(map[string]string)
		var currentIPCNo = 0
		var bid = ""
		var stationID = ""
		var cboxip = ""
		var err error

		for _, box := range msg.Infos {
			if box != nil {
				boxip := box["智能箱ip"]
				if boxip != nil {
					cboxip = boxip.(string)
				}
				if cboxip != "" && cboxip != bip {
					bid, stationID, err = getStationByID(cboxip)
					if err != nil || bid == "" {
						continue
					}
					currentIPCNo = 0
				}
				cboxip = bip
				mapParams["ip"] = box["摄像机ip"].(string)
				mapParams["id_in_box"] = "Cam" + strconv.Itoa(currentIPCNo)
				rtsp := box["rtsp地址"]
				if rtsp != nil {
					srtsp, ok := rtsp.(string)
					if ok {
						mapParams["rtsp"] = srtsp
					}

				}

				mapParams["box_id"] = bid
				b := box["B"]
				p := box["P"]
				if b != nil && p != nil {
					mapParams["b"] = fmt.Sprintf("%f", b.(float64))
					mapParams["p"] = fmt.Sprintf("%f", p.(float64))
				} else {
					mapParams["b"] = "-1"
					mapParams["p"] = "-1"
				}
				mapParams["cno"] = strconv.Itoa(currentIPCNo)

				currentIPCNo++
				createIPC(mapParams, stationID)

			}
		}
	}
	return ret
}
